﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Media.Imaging;
using System.Windows;
using TorchView.Imaging;
using TorchView.GameContent.Data;
using System.Xml.Linq;

namespace TorchView.GameContent
{
  public sealed class ImageSet : IEnumerable<KeyValuePair<string, ImageSet.Image>>
  {
    private Dictionary<string, Image> _Images = new Dictionary<string, Image>();
    private ImageSet() { }

    /// <summary>
    /// Get the image by the specified icon name
    /// </summary>
    /// <param name="iconName">Name of the image to retrieve</param>
    /// <returns>The image if one is found, null if one is not found</returns>
    public Image this[string iconName]
    {
      get
      {
        Image image;
        if (_Images.TryGetValue(iconName, out image))
          return image;
        return null;
      }
    }

    internal static IEnumerable<ImageSet> LoadImages(IEnumerable<string> imageSets)
    {
      using (DDSLoader loader = new DDSLoader())
      {
        foreach (var set in imageSets)
        {
          ImageSet imageSet = LoadImageSet(loader, set);
          yield return imageSet;
        }
      }
    }

    /// <summary>
    /// Load an image set from a pak filename
    /// </summary>
    /// <param name="imageSetFile">Image set pak filename</param>
    /// <returns>Image set for the file.</returns>
    public static ImageSet LoadImages(string imageSetFile)
    {
      using (DDSLoader loader = new DDSLoader())
        return LoadImageSet(loader, imageSetFile);
    }

    private static ImageSet LoadImageSet(DDSLoader loader, string set)
    {
      ImageSet imageSet = new ImageSet();
      var stream = PakReader.OpenFile(set);
      var root = XElement.Load(stream, LoadOptions.None);
      string imageFile = GetAttributeValue(root, "Imagefile");
      var imageDDS = PakReader.OpenFile(imageFile);
      var masterImage = loader.Load(imageDDS);

      foreach (var i in root.Elements("Image"))
      {
        string name = GetAttributeValue(i, "Name");
        if (string.IsNullOrEmpty(name))
          continue;

        Int32Rect crop = new Int32Rect(
          GetAttributeValue(i, "XPos", 0),
          GetAttributeValue(i, "YPos", 0),
          GetAttributeValue(i, "Width", 0),
          GetAttributeValue(i, "Height", 0));

        imageSet._Images.Add(name, new Image(masterImage, crop));
      }
      return imageSet;
    }

    private static string GetAttributeValue(XElement element, string attributeName)
    {
      var attribute = element.Attribute(attributeName);
      if (attribute != null)
        return attribute.Value;
      return null;
    }

    private static int GetAttributeValue(XElement element, string attributeName, int defaultValue)
    {
      var attribute = element.Attribute(attributeName);
      if (attribute != null)
      {
        int value;
        if (int.TryParse(attribute.Value, out value))
          return value;
      }
      return defaultValue;
    }

    public IEnumerator<KeyValuePair<string, ImageSet.Image>> GetEnumerator()
    {
      return _Images.GetEnumerator();
    }

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
      return GetEnumerator();
    }

    public sealed class Image
    {
      private WeakReference _CurrentImage;
      private Int32Rect _CropArea;
      private BitmapSource _Master;

      internal Image(BitmapSource master, Int32Rect cropArea)
      {
        _Master = master;
        _CropArea = cropArea;
      }

      public BitmapSource GetBitmapSource()
      {
        var currentImage = _CurrentImage == null ? null : _CurrentImage.Target as BitmapSource;
        if (currentImage != null)
          return currentImage;
        CroppedBitmap bitmap = new CroppedBitmap(_Master, _CropArea);
        bitmap.Freeze();
        _CurrentImage = new WeakReference(bitmap);
        return bitmap;
      }
    }
  }
}
